package com.wyw.core.config;

import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.annotation.Resource;
import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Validator;

import net.sf.ehcache.Cache;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.input.SAXBuilder;
import org.jdom.transform.JDOMSource;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.support.FileSystemXmlApplicationContext;

import com.wyw.core.secu.dto.XmlConfigType;
import com.wyw.core.util.CacheManager;



public class XmlConfigListInitial implements InitializingBean,ApplicationContextAware{
	protected final Log logger = LogFactory.getLog(getClass());
	
	private boolean isLoadInit ;
	public boolean getIsLoadInit() {
		return isLoadInit;
	}
	public void setIsLoadInit(boolean isLoadInit) {
		this.isLoadInit = isLoadInit;
	}
	private String xmlConfigTypeDef;
	public String getXmlConfigTypeDef() {
		return xmlConfigTypeDef;
	}
	public void setXmlConfigTypeDef(String xmlConfigTypeDef) {
		this.xmlConfigTypeDef = xmlConfigTypeDef;
	}
	private  String configPath;
	private  String configXsdPath;

	public String getConfigXsdPath() {
		return configXsdPath;
	}
	public void setConfigXsdPath(String configXsdPath) {
		this.configXsdPath = configXsdPath;
	}

	private ApplicationContext applicationContext;

	
	public String getConfigPath() {
		return configPath;
	}
	public void setConfigPath(String configPath) {
		this.configPath = configPath;
	}
	
	private Cache ehcache;
	//取配置文件中的ehcache
	@Resource(name="ehcache")
	public void setEhcache(Cache ehcache){
		this.ehcache=ehcache;
	}
	public void toLoadCfonigXmlList(){
		List fileList =null;
	}
	
	public List doInitialConfigXmlList(){
		try{
			org.springframework.core.io.Resource xmlPathResource =applicationContext.getResource(configPath);
			org.springframework.core.io.Resource xmlConfigTypeDefResource =applicationContext.getResource(xmlConfigTypeDef);
			parseXmlConfigType(xmlConfigTypeDefResource);
			//取得路径
			File dir= xmlPathResource.getFile();
			List<File> xmlList = new ArrayList();
			//获取所有文件
			queryConfigList(dir,xmlList);
			validateAndContactXmlToEncache(xmlList);//合并检查并保存文件到encache
			parseAllXmlConfigToInstance();//解析所有的xml文件
			System.out.println("validate ok ");
		return xmlList;
		}catch(Exception e){
			e.printStackTrace();
			return null;
		}		
	}
	
	public void parseAllXmlConfigToInstance()throws Exception{
		HashMap xmlConfigTypeDefinitions=(HashMap)ehcache.get(CacheManager.xml_config_type_definitions).getObjectValue();
		HashMap xmlConfigFiles=(HashMap)ehcache.get(CacheManager.xml_config_files).getObjectValue();
		String[] xmlConfigNames = new String[xmlConfigFiles.size()];
		xmlConfigFiles.keySet().toArray(xmlConfigNames);
		Document document;
		XmlConfigType xmlConfigType;
		for(String xmlConfigName : xmlConfigNames){
			xmlConfigType=(XmlConfigType)xmlConfigTypeDefinitions.get(xmlConfigName);
			if(xmlConfigType !=null){
				document=(Document)xmlConfigFiles.get(xmlConfigName);
				parseXmlConfigToInstance(xmlConfigType,document);
			}
		}
	}
	
	public void parseXmlConfigToInstance(XmlConfigType xmlConfigType,Document xmlConfig)throws Exception{
		if(StringUtils.isEmpty(xmlConfigType.getParseClass())){
			return ;
		}
		XmlConfigParse xmlConfigParse=(XmlConfigParse)Class.forName(xmlConfigType.getParseClass()).newInstance();
		xmlConfigParse.parse(xmlConfigType, xmlConfig);
	}
	
	//获取配置文件定义配置
	public void parseXmlConfigType(org.springframework.core.io.Resource xmlConfigTypeDefResource)throws Exception{
		SAXBuilder reader = new SAXBuilder();
		//System.out.println(xmlConfigTypeDefResource.getFile().getName());
		Document document =reader.build(xmlConfigTypeDefResource.getFile()) ;
		Map configTypeMap = new HashMap();
		List<Element> configTypeList=document.getRootElement().getChildren();
		XmlConfigType xmlConfigType;
		for(Element configType:configTypeList){
			xmlConfigType= new XmlConfigType();
			xmlConfigType.setXmlConfigType(configType.getAttributeValue("id"));
			xmlConfigType.setDesc(configType.getChildText("desc"));
			xmlConfigType.setParseClass(configType.getChildText("parseClass"));
			xmlConfigType.setXsd(configType.getChildText("xsd"));
			configTypeMap.put(xmlConfigType.getXmlConfigType(), xmlConfigType);
		}
		net.sf.ehcache.Element config=new  net.sf.ehcache.Element(CacheManager.xml_config_type_definitions,configTypeMap);
		ehcache.put(config);
	}
	
	
	private void validateAndContactXmlToEncache(List<File> xmlList){
		HashMap configMap = new HashMap();
		for(File xmlFile:xmlList){
			contactConfig( configMap, xmlFile); //合并文件
		}
		//验证合法性
		//validateAllXml(configMap);
		//放缓存
		net.sf.ehcache.Element config=new  net.sf.ehcache.Element(CacheManager.xml_config_files,configMap);
		ehcache.put(config);
	}
	
	private void contactConfig(HashMap configMap,File xmlFile){
		SAXBuilder reader = new SAXBuilder();
		String configTypeName;
		try{
			Document document =reader.build(xmlFile) ;
			configTypeName = document.getRootElement().getName();
			
			if(!checkXmlTypeHasRegistered(configTypeName)){//未注册
				return ;
			}
			Document cacheDocument =(Document) configMap.get(configTypeName);
			if(cacheDocument == null){
				cacheDocument=document;
				configMap.put(configTypeName, cacheDocument);
			}else{
				Element cacheElementRoot =cacheDocument.getRootElement();
				List<Element> documentChildList = document.getRootElement().getChildren();
				for(int i =documentChildList.size()-1;i>=0; i--){
					Element el = documentChildList.get(i);
					el.detach();
					cacheElementRoot.addContent(el);				
				}
			}
		}catch(Exception e){
			// e.printStackTrace();
			System.out.println("读取xml文件出错:"+xmlFile.getName());
		}
	}
	
	private boolean checkXmlTypeHasRegistered(String configType){
		HashMap xmlConfigTypeDefinitions=(HashMap)ehcache.get(CacheManager.xml_config_type_definitions).getObjectValue();
		return xmlConfigTypeDefinitions.get(configType)!=null; 
	}
	
	
	private void validateAllXml(HashMap configMap ){
		Set configTypeSet=configMap.keySet();
		Iterator iterator = configTypeSet.iterator();
		String configType;
		while(iterator.hasNext()){
			configType=(String)iterator.next();
			validateXml(configType,(Document)configMap.get(configType));
		}
	}
	
	private void validateXml(String configType,Document document){
		JDOMSource jDOMSource = new JDOMSource(document);
		 try{
			File schema = getXMLSchecma(configType);
			Validator validator =SchemaFactory.newInstance(ConfigConstant.www_w3_org_XMLSchema).newSchema(schema).newValidator();
			validator.validate(jDOMSource);
		 }catch(Exception e){e.printStackTrace();}
	}
	
	private File getXMLSchecma(String xmlTyle)throws Exception{
		String xsdPath = configXsdPath+"/"+xmlTyle+".xsd";
		try{
		org.springframework.core.io.Resource resource =applicationContext.getResource(xsdPath);
			return resource.getFile();
		}catch(Exception e){
			System.out.println("没有找到文件"+xsdPath);
			throw e;
		}
	}
	
	private void queryConfigList(File dir,List fileList){
		File[] files=dir.listFiles();
		for(File fi:files){
			if(fi.isDirectory()){
				queryConfigList(fi,fileList);
			}else{
				if(fi.getName().endsWith(".xml")){
					fileList.add(fi);
				}
			}
		}
	}
	@Override
	public void afterPropertiesSet() throws Exception {
		// TODO Auto-generated method stub
		if(!this.isLoadInit){
			return ;
		}
		ehcache.removeAll();//清空
		logger.info("【加载配置开始】");
		List xmlList = doInitialConfigXmlList();
		
	}
 
	@Override
	public void setApplicationContext(ApplicationContext applicationContext)
			throws BeansException {
		// TODO Auto-generated method stub
		this.applicationContext=applicationContext;
	}
 
	public static void main(String[] args)throws Exception{
		 
		ApplicationContext ctx = new FileSystemXmlApplicationContext("F:/workspace/spring-web/WebContent/WEB-INF/p_context.xml");
		//ApplicationContext ctx = new ClassPathXmlApplicationContext("/WEB-INF/p_context.xml");
	}
 
	
	
}
